<?php
/*
 * Copyright (c) 2009 Tom Smith (tom@takeontom.com).
 * 
 * Distributed under the terms of the GNU Lesser General Public License.
 * 
 * ---------------------------------------------------------------------------------
 * 
 * This file is part of Seraph PHP Framework.
 *
 * Seraph PHP Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Seraph PHP Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Seraph PHP Framework.  If not, see <http://www.gnu.org/licenses/>.
*/


class EntityContainer implements Countable, Iterator	{
	protected $entities = array();
	
	/**
	 * Get an entity from the container
	 * 
	 * If the entity is not in the container then will return null
	 * 
	 * 
	 * @param $type
	 * @param $key
	 * @return Entity
	 */
	public function getEntity($type, array $key)	{
		if ($type instanceof Entity)	{
			return $this->getEntityOfSameType($type, $key);
		}
		
		if ($this->isEntityInContainer($type, $key))	{
			return $this->getEntityFromContainer($type, $key);
		}
		
		return null;
	}
	
	/**
	 * Attemps tp get an entity of the same type as the passed entity.
	 * 
	 * @param $entity
	 * @param $key
	 * @return Entity
	 */
	public function getEntityOfSameType(Entity $entity, array $key)	{
		if ($this->isEntityInContainer($entity, $key))	{
			return $this->getEntityFromContainer($entity, $key);
		}
		
		if ($entity instanceof Entity)	{
			$this->addEntity($entity);
			return $entity;
		}
		
		return null;
	}
	
	/**
	 * Get the specified entity from the container.
	 * 
	 * Will return false if not found.
	 * 
	 * @param $type
	 * @param $key
	 * @return Entity
	 */
	protected function getEntityFromContainer($type, array $key)	{
		if ($type instanceof Entity)	{
			$type = get_class($type);
		}
		return $this->entities[$this->generateKeyHash($type, $key)];
	}
	
	public function addEntity(Entity $entity)	{
		$this->entities[$this->generateEntityHash($entity)] = $entity;
	}
	
	/**
	 * Add the contents of a container to this container.
	 * 
	 * @param EntityContainer $container
	 */
	public function addContainerContents(EntityContainer $container)	{
		foreach($container as $e)	{
			$this->addEntity($e);
		}
	}
	
	/**
	 * Generate a unique hash for the given entity.
	 * 
	 * Simply passes the interesting bits of the entity to generateKeyHash()
	 * 
	 * @param $entity
	 * @return string
	 */
	public function generateEntityHash(Entity $entity)	{
		return $this->generateKeyHash(get_class($entity), $entity->getPrimaryKeyValue());
	}
	
	/**
	 * Generate a hash which can be used to uniquely identify the object
	 * 
	 * @param $key
	 * @return string
	 */
	public function generateKeyHash($type, array $key)	{
		if ($type instanceof Entity)	{
			$type = get_class($type);
		}
		//sort before hashing to ensure consistent results
		ksort($key);
		return md5($type . implode('', $key));
	}
	
	/**
	 * Checks whether the entity is in the container or not.
	 * 
	 * @param $type
	 * @param $key
	 * @return bool
	 */
	public function isEntityInContainer($type, array $key)	{
		if ($type instanceof $type)	{
			$type = get_class($type);
		}
		return (isset($this->entities[$this->generateKeyHash($type, $key)]));
	}
	
	
	/**
	 * For Countable interface
	 */
	public function count()	{
		return count($this->entities);
	}
	
	function rewind() {
		reset($this->entities);
	}

	function current() {
		return current($this->entities);
	}

	function key() {
		return key($this->entities);
	}

	function next() {
		next($this->entities);
	}

	function valid() {
		return current($this->entities);
	} 
}
?>